#include "lcd.h"

uint8_t current_column;
uint8_t current_page;

void lcd_init(void)
{
	uint8_t ratio;
	uint8_t volume;
	uint8_t LCD_Contrast = 5;

	ratio = 0x20 | LCD_Contrast;
	volume = 33;

	// Set LCD_A0 as output
	LCD_DDR |= (1<<LCD_A0);

	// LCD BIAS setting (11) 
	lcd_command(LCD_BIAS_SET_19);

	// ADC selection (8)
	lcd_command(LCD_ADC_SET_REVERSE);

	// Common output state selection (4)
	lcd_command(LCD_COMMON_NORMAL);

	// Initial display line set
	lcd_command(LCD_DISPLAY_LINE_0);

	// Set built in resistance ratio (17)
	lcd_command(ratio);

	// Electronic volume control (18) command & value
	lcd_command(LCD_ELECTRONIC_SET);
	lcd_command(volume);

	// Power control setting (16)
	lcd_command(LCD_POWER_SET_ALL_ON);

	//LCD display on
	lcd_command(LCD_DISPLAY_ON);

	//Entire display on
	lcd_command(LCD_DISPLAY_ALL_POINTS_NORMAL);

}

void lcd_command(uint8_t command)
{
	//LCD to instruction mode
	LCD_INSTRUCTION_MODE();

	// Select card
	spi_select_lcd();

	spi_write(command);
	
	// Unselect card
	spi_select_can();

	_delay_us(10);
}

void lcd_write_data(uint8_t data)
{
	// LCD to data mode
	LCD_DATA_MODE();
	
	spi_select_lcd();

	spi_write(data);
	current_column++;

	spi_select_can();

	LCD_INSTRUCTION_MODE();

	_delay_us(5);

}

void lcd_select_line(uint8_t page)
{

	if(current_page != page && page >= 0 && page <= 7)
	{
		// Initial display line set
		lcd_command(LCD_DISPLAY_LINE_0);	

		// Select page address
		lcd_command(0xB0 | page); 

		// Select column 0
		lcd_command(0x10 | 0);
		lcd_command(0x00 | 0);

		current_column = 0;
		current_page = page;
	}
}

void lcd_select_column(uint8_t column)
{
	// Select column address bits
	uint8_t col_high = (column & 0xF0) >> 4;
	uint8_t col_low = column & 0x0F;
	lcd_command(0x10 | col_high);
	lcd_command(0x00 | col_low);

	current_column = column;
}

void lcd_clear_display(void)
{
	uint8_t i;
	uint8_t j;
	for(i = 0; i < 7; i++)
	{
	
		lcd_select_line(i);
		
		// Select display line start
		for(j = 0; j < 131; j++)
		{
			
			lcd_write_data(0x00);
		}
	}

	// Resets cursor position to top of the display
	lcd_select_line(0);

	//lcd_refresh();
}

void lcd_clear_command_line(void)
{
	uint8_t j = 0;

	lcd_select_line(7);
	// Select display line start
	for(j = 0; j < 131; j++)
	{
			
		lcd_write_data(0x00);
	}
	
	// Resets cursor position to top of the display
	lcd_select_line(0);
}

void lcd_refresh(void)
{
	//LCD display on
	lcd_command(LCD_DISPLAY_OFF);
	lcd_command(LCD_DISPLAY_ON);
}

int8_t lcd_write_P(uint8_t line, char *c)
{
	//uint8_t i = 0;
	if(line != current_page)
		lcd_select_line(line);

	while(pgm_read_byte(c) != '\0' && current_column < 126)
	{
		lcd_write_char(pgm_read_byte(c));
		c++;
	}
	// Writing over line width
	if(current_column >= 126)
		return -1;
	return 0;
}
/* Writes data to current line. Use '\0' to end char array.
   Returns 0 if writes were succesful.
   Returns -1 if trying to write beyond line's width */
int8_t lcd_write(uint8_t line, char *c)
{
	//uint8_t i = 0;
	if(line != current_page)
		lcd_select_line(line);

	while(*c != '\0' && current_column < 126)
	{
		lcd_write_char(*c);
		c++;
	}
	// Writing over line width
	if(current_column >= 126)
		return -1;
	return 0;
}

void lcd_write_char(char c)
{
	switch(c)
		{
			case 'A':
			case 'a':
				lcd_write_data(0x7E);
				lcd_write_data(0x11);
				lcd_write_data(0x11);
				lcd_write_data(0x11);
				lcd_write_data(0x7E);
				lcd_write_data(0x00);
				break;
			case 'B':
			case 'b':
				lcd_write_data(0x7F);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x36);
				lcd_write_data(0x00);
				break;
			case 'C':
			case 'c':
				lcd_write_data(0x3E);
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x22);
				lcd_write_data(0x00);
				break;
			case 'D':
			case 'd':
				lcd_write_data(0x7F);
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x3E);
				lcd_write_data(0x00);
				break;
			case 'E':
			case 'e':
				lcd_write_data(0x7F);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x41);
				lcd_write_data(0x00);
				break;
			case 'F':
			case 'f':
				lcd_write_data(0x7F);
				lcd_write_data(0x09);
				lcd_write_data(0x09);
				lcd_write_data(0x09);
				lcd_write_data(0x01);
				lcd_write_data(0x00);
				break;
			case 'G':
			case 'g':
				lcd_write_data(0x3E);
				lcd_write_data(0x41);
				lcd_write_data(0x51);
				lcd_write_data(0x51);
				lcd_write_data(0x72);
				lcd_write_data(0x00);
				break;
			case 'H':
			case 'h':
				lcd_write_data(0x7F);
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x7F);
				lcd_write_data(0x00);
				break;
			case 'I':
			case 'i':
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x7F);
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x00);
				break;
			case 'J':
			case 'j':
				lcd_write_data(0x20);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x3F);
				lcd_write_data(0x00);
				break;
			case 'K':
			case 'k':
				lcd_write_data(0x7F);
				lcd_write_data(0x08);
				lcd_write_data(0x14);
				lcd_write_data(0x22);
				lcd_write_data(0x41);
				lcd_write_data(0x00);
				break;
			case 'L':
			case 'l':
				lcd_write_data(0x7F);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x00);
				break;
			case 'M':
			case 'm':
				lcd_write_data(0x7F);
				lcd_write_data(0x02);
				lcd_write_data(0x04);
				lcd_write_data(0x02);
				lcd_write_data(0x7F);
				lcd_write_data(0x00);
				break;
			case 'N':
			case 'n':
				lcd_write_data(0x7F);
				lcd_write_data(0x04);
				lcd_write_data(0x08);
				lcd_write_data(0x10);
				lcd_write_data(0x7F);
				lcd_write_data(0x00);
				break;
			case 'O':
			case 'o':
				lcd_write_data(0x3E);
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x41);
				lcd_write_data(0x3E);
				lcd_write_data(0x00);
				break;
			case 'P':
			case 'p':
				lcd_write_data(0x7F);
				lcd_write_data(0x11);
				lcd_write_data(0x11);
				lcd_write_data(0x11);
				lcd_write_data(0x0E);
				lcd_write_data(0x00);
				break;
			case 'Q':
			case 'q':
				lcd_write_data(0x3E);
				lcd_write_data(0x41);
				lcd_write_data(0x51);
				lcd_write_data(0x61);
				lcd_write_data(0x3E);
				lcd_write_data(0x00);
				break;
			case 'R':
			case 'r':
				lcd_write_data(0x7F);
				lcd_write_data(0x11);
				lcd_write_data(0x11);
				lcd_write_data(0x11);
				lcd_write_data(0x6E);
				lcd_write_data(0x00);
				break;
			case 'S':
			case 's':
				lcd_write_data(0x26);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x32);
				lcd_write_data(0x00);
				break;
			case 'T':
			case 't':
				lcd_write_data(0x01);
				lcd_write_data(0x01);
				lcd_write_data(0x7F);
				lcd_write_data(0x01);
				lcd_write_data(0x01);
				lcd_write_data(0x00);
				break;
			case 'U':
			case 'u':
				lcd_write_data(0x3F);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x3F);
				lcd_write_data(0x00);
				break;
			case 'V':
			case 'v':
				lcd_write_data(0x1F);
				lcd_write_data(0x20);
				lcd_write_data(0x40);
				lcd_write_data(0x20);
				lcd_write_data(0x1F);
				lcd_write_data(0x00);
				break;
			case 'W':
			case 'w':
				lcd_write_data(0x3F);
				lcd_write_data(0x40);
				lcd_write_data(0x30);
				lcd_write_data(0x40);
				lcd_write_data(0x3F);
				lcd_write_data(0x00);
				break;
			case 'X':
			case 'x':
				lcd_write_data(0x63);
				lcd_write_data(0x14);
				lcd_write_data(0x08);
				lcd_write_data(0x14);
				lcd_write_data(0x63);
				lcd_write_data(0x00);
				break;
			case 'Y':
			case 'y':
				lcd_write_data(0x03);
				lcd_write_data(0x04);
				lcd_write_data(0x78);
				lcd_write_data(0x04);
				lcd_write_data(0x03);
				lcd_write_data(0x00);
				break;
			case 'Z':
			case 'z':
				lcd_write_data(0x61);
				lcd_write_data(0x51);
				lcd_write_data(0x49);
				lcd_write_data(0x45);
				lcd_write_data(0x43);
				lcd_write_data(0x00);
				break;
			/*				
			case 'a':
				lcd_write_data(0x32);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x3E);
				lcd_write_data(0x40);
				lcd_write_data(0x00);
				break;
			case 'b':
				lcd_write_data(0x7F);
				lcd_write_data(0x48);
				lcd_write_data(0x48);
				lcd_write_data(0x48);
				lcd_write_data(0x30);
				lcd_write_data(0x00);
				break;
			case 'c':
				lcd_write_data(0x44);
				lcd_write_data(0x42);
				lcd_write_data(0x7F);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x00);
				break;
			*/
			case '1':
				lcd_write_data(0x44);
				lcd_write_data(0x42);
				lcd_write_data(0x7F);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x00);
				break;
			case '2':
				lcd_write_data(0x42);
				lcd_write_data(0x61);
				lcd_write_data(0x51);
				lcd_write_data(0x49);
				lcd_write_data(0x46);
				lcd_write_data(0x00);
				break;
			case '3':
				lcd_write_data(0x22);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x36);
				lcd_write_data(0x00);
				break;
			case '4':
				lcd_write_data(0x18);
				lcd_write_data(0x14);
				lcd_write_data(0x12);
				lcd_write_data(0x7F);
				lcd_write_data(0x10);
				lcd_write_data(0x00);
				break;
			case '5':
				lcd_write_data(0x4F);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x31);
				lcd_write_data(0x00);
				break;				
			case '6':
				lcd_write_data(0x3E);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x32);
				lcd_write_data(0x00);
				break;
			case '7':
				lcd_write_data(0x01);
				lcd_write_data(0x01);
				lcd_write_data(0x71);
				lcd_write_data(0x09);
				lcd_write_data(0x07);
				lcd_write_data(0x00);
				break;
			case '8':
				lcd_write_data(0x36);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x36);
				lcd_write_data(0x00);
				break;
			case '9':
				lcd_write_data(0x26);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x49);
				lcd_write_data(0x3E);
				lcd_write_data(0x00);
				break;
			case '0':
				lcd_write_data(0x3E);
				lcd_write_data(0x45);
				lcd_write_data(0x49);
				lcd_write_data(0x51);
				lcd_write_data(0x3E);
				lcd_write_data(0x00);
				break;
			case ' ':
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				break;
			case '-':
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x00);
				break;
			case '+':
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x7F);
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x00);
				break;
			case '*':
				lcd_write_data(0x2A);
				lcd_write_data(0x1C);
				lcd_write_data(0x7F);
				lcd_write_data(0x1C);
				lcd_write_data(0x2A);
				lcd_write_data(0x00);
				break;
			case '>':
				lcd_write_data(0x08);
				lcd_write_data(0x08);
				lcd_write_data(0x2A);
				lcd_write_data(0x1C);
				lcd_write_data(0x08);
				lcd_write_data(0x00);
				break;
			case '/':
				lcd_write_data(0x40);
				lcd_write_data(0x20);
				lcd_write_data(0x10);
				lcd_write_data(0x08);
				lcd_write_data(0x04);
				lcd_write_data(0x00);
				break;
			case ':':
				lcd_write_data(0x00);
				lcd_write_data(0x66);
				lcd_write_data(0x66);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				break;
			case '.':
				lcd_write_data(0x00);
				lcd_write_data(0x60);
				lcd_write_data(0x60);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				lcd_write_data(0x00);
				break;
			case '_':
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x40);
				lcd_write_data(0x00);
				break;
			case '@': // Degree sign
				lcd_write_data(0x00);
				lcd_write_data(0x06);
				lcd_write_data(0x09);
				lcd_write_data(0x09);
				lcd_write_data(0x06);
				lcd_write_data(0x00);
				break;
			case '|': // Plane
				lcd_write_data(0x01);
				lcd_write_data(0x03);
				lcd_write_data(0x06);
				lcd_write_data(0x0C);
				lcd_write_data(0x0C);
				lcd_write_data(0x0C);
				lcd_write_data(0x0C);
				lcd_write_data(0x2D);
				lcd_write_data(0x3F);
				lcd_write_data(0x1E);
				lcd_write_data(0x0C);
				lcd_write_data(0x0C);
				lcd_write_data(0x08);
				lcd_write_data(0x00);
				break;
			default:
				// Character not supported
				lcd_write_data(0x3E);
				lcd_write_data(0x22);
				lcd_write_data(0x22);
				lcd_write_data(0x22);
				lcd_write_data(0x3E);
				lcd_write_data(0x00);
				break;
		}
}
